# -*- coding: utf-8 -*-
"""
Date: 2021-12-06
Author: J z
"""
import math
import random

from app.const.enums.activity_enums import ServiceAffairStatus, AffairStatus, GameRankKey
from app.user.component.core.base_component import BaseComponent
from common.tips_info import CodeInfo
from framework.dal.dal_manager import PeeweeTransaction, TransactionPropagation
from framework.dal.gameconfig.game_env import get_config_env_set
from framework.dal.repository_impl import RoleRepository, PayRecordRepository, SeatRepository, RoleAffairRepository, \
    OrderSendRepository, ServiceRoleAffairRepository
from framework.distribute import mutex
from framework.distribute.lock_define import SeatLock, SeatIdLock
from framework.firefly_dc.error_handle import GameException
from utils.time_utils import getCT, getCountdown
from utils.rank_utils import game_rank


class RoleComponent(BaseComponent):
    """
    角色组件
    """

    def enter_main_interface(self, rid):
        """
        主界面
        :return:
        """
        result = dict()
        seat_list = []
        already_match_seat = 0

        # 全部座位信息
        seats = SeatRepository.query_all()
        # 获取当前无人且有服务者的座位
        service_role_guid_list = []
        for seat in seats:
            # 服务者rids
            service_role_guid_list.append(seat.service_role_guid)
            if not seat.role_guid and seat.service_role_guid:
                seat_list.append(seat)

            if seat.role_guid == rid:
                already_match_seat = seat.seat_id

        # 当前所有服务者信息
        service_role_list = RoleRepository.filter_by_rid_list(rid_list=service_role_guid_list)

        # 头像列表
        head_list = []

        for service_role in service_role_list:
            head_list.append(service_role.head)

        # 当前空余座位数量(无人且有服务者)
        can_use_seat = len(seat_list)

        # 是否有未匹配订单

        # 模拟添加排行榜
        # game_rank.add_score_to_rank(rid, 10, GameRankKey.PlayerMatchCountRank)

        # 玩家匹配次数排行榜
        player_count_rank_list = game_rank.get_range_detail(GameRankKey.PlayerMatchCountRank, end=9)
        player_time_rank_list = game_rank.get_range_detail(GameRankKey.PlayerMatchTimeRank, end=9)
        service_count_rank_list = game_rank.get_range_detail(GameRankKey.ServiceCountRank, end=9)
        service_time_rank_list = game_rank.get_range_detail(GameRankKey.ServiceTimeRank, end=9)

        result['HeadList'] = head_list
        result['CanUseSeat'] = can_use_seat
        result['PlayerMatchCountRank'] = player_count_rank_list
        result['PlayerMatchTimeRank'] = player_time_rank_list
        result['ServiceCountRank'] = service_count_rank_list
        result['ServiceTimeRank'] = service_time_rank_list
        result['AlreadyMatchSeat'] = already_match_seat

        return result

    @staticmethod
    def pay_pre_check(role_guid):
        """
        下单前置校验
        :return:
        """
        # 下单前置校验
        role_record = RoleRepository.get_by_rid(role_guid)
        # 是否还有位置

        # 当前已绑定事件
        if role_record.affair_id:
            raise GameException(CodeInfo.AlreadyChoose)
        # 不存在未匹配订单(防止重复下单)
        pay_record = PayRecordRepository.get_not_match_order_by_rid(role_guid)
        if not pay_record:
            raise GameException(CodeInfo.OrderNotExist)

    def role_choose_seat(self, role_guid):
        """
        抽取号码

        点击按钮=>请求前置校验=>客户端调用第三方支付=>支付成功 => 写入订单表(状态为未匹配 自动调用一次失败则再次点击手动调用 不需要再次支付)
        未匹配订单可以申请结束订单退款
        :return:
        """

        result = {}
        seat_list = []
        role_record = RoleRepository.get_by_rid(role_guid)

        # 当前已绑定事件
        if role_record.affair_id:
            raise GameException(CodeInfo.AlreadyChoose)

        # 当前存在未匹配订单
        pay_record = PayRecordRepository.get_not_match_order_by_rid(role_guid)
        if not pay_record:
            raise GameException(CodeInfo.OrderNotExist)

        # 加锁: 防止并发
        with mutex.KeyMutex(SeatLock.G_SEAT_LOCK):
            seats = SeatRepository.query_all()
            # 获取当前无人且有服务者的座位
            for seat in seats:
                if not seat.role_guid and seat.service_role_guid:
                    seat_list.append(seat)

            if not seat_list:
                raise GameException(CodeInfo.CurNotSeat)

            # 随机抽取座位
            lucky_seat_obj = random.choice(seat_list)

            service_role = RoleRepository.get_by_rid(lucky_seat_obj.service_role_guid)
            if not service_role:
                raise GameException("服务角色异常")
            service_role_affair = ServiceRoleAffairRepository.get_by_affair_id(service_role.service_affair_id)
            if not service_role_affair:
                raise GameException("服务者事件不存在")

            # 事务
            with PeeweeTransaction(propagation=TransactionPropagation.REQUIRES_NEW):
                # 创建事件
                affair = RoleAffairRepository.create(role_guid,
                                                     lucky_seat_obj.seat_id,
                                                     lucky_seat_obj.service_role_guid
                                                     )

                # 绑定事件
                role_record.affair_id = affair.affair_id
                pay_record.relation_affair_id = affair.affair_id
                # 写入服务者服务对象
                service_role_list = service_role_affair.service_role_list
                service_role_list.append(role_guid)
                service_role_affair.service_role_list = service_role_list
                # 写入座位
                lucky_seat_obj.role_guid = role_guid

                PayRecordRepository.save(pay_record)
                RoleRepository.save(role_record)
                ServiceRoleAffairRepository.save(service_role_affair)
                SeatRepository.save(lucky_seat_obj)

                result["SeatId"] = affair.seat_id
        return result

    def get_role_info(self, rid):
        """获取角色信息"""
        role_record = RoleRepository.get_by_rid(rid)
        return {"Role": role_record.asdict()}

    def clean_role(self, rid, cost_amount):
        """
        玩家结算(支付成功后调用)
        :param rid:
        :param cost_amount: 支付金额
        :return:
        """

        # 取消绑定事件
        role_record = RoleRepository.get_by_rid(rid)
        if not role_record:
            raise GameException("角色不存在")

        if not role_record.affair_id:
            raise GameException("当前未绑定事件")

        affair = RoleAffairRepository.get_by_affair_id(role_record.affair_id)
        if not affair:
            raise GameException("事件不存在")

        seat_record = SeatRepository.get_by_seat_id(affair.seat_id)
        if not seat_record:
            raise GameException("座位Id错误")
        pay_record = PayRecordRepository.get_by_relation_affairid(role_record.affair_id)
        if not pay_record:
            raise GameException("订单不存在")

        # 结束时间记录
        affair.end_time = getCT()
        # 取消绑定事件
        role_record.affair_id = ""
        # 取消座位绑定
        seat_record.role_guid = ""
        # 修改事件状态
        affair.affair_status = AffairStatus.Close

        # 写入支付金额
        pay_record.amount = cost_amount

        # 事务
        with PeeweeTransaction(propagation=TransactionPropagation.REQUIRES_NEW):
            PayRecordRepository.save(pay_record)
            RoleAffairRepository.save(affair)
            SeatRepository.save(seat_record)
            RoleRepository.save(role_record)

        return {}

    @staticmethod
    def filter_service_role_affair_history(rid, page, page_size):
        """查看历史匹配事件(详情下发)"""
        # 偏移量
        offset = (page - 1) * page_size
        records = ServiceRoleAffairRepository.filter_by_rid_order_column(rid, page_size, offset)
        history_service_role_list = []
        if not records:
            return {"status": True, "HistoryServiceRoleList": history_service_role_list}
        rids = []
        for record in records:
            rids.extend(record.service_role_list)
        role_records = RoleRepository.filter_by_rid_list(list(set(rids)))
        # 构造映射
        role_map_dict = {}
        for role in role_records:
            if role.role_guid not in role_map_dict:
                role_map_dict[role.role_guid] = role

        for r in records:
            role_info_list = []
            for role_guid in r.service_role_list:
                role_obj = role_map_dict.get(role_guid)
                if role_obj:
                    role_info_list.append({"NickName": role_obj.nick_name, "Head": role_obj.head})

            history_service_role_list.append({"AffairId": r.affair_id, "LockSeatId": r.lock_seat_id,
                                              "ServiceRoleList": r.service_role_list, "SignTime": r.sign_time,
                                              "EndTime": r.end_time, "Reward": r.reward,
                                              "AffairStatus": r.affair_status, "RoleInfoList": role_info_list})

        return {"status": True, "HistoryServiceRoleList": history_service_role_list}

    def service_role_check_in(self, rid, seat_id):
        """
        服务者签到
        :param rid:
        :param seat_id: 座位id
        :return:
        """
        # 审核资质(女生 是否上传图片等)  可支持线上预约到店扫码签到

        role_record = RoleRepository.get_by_rid(rid)
        if not role_record:
            raise GameException("无角色")
        if not role_record.is_service:
            raise GameException("未审核通过")
        # 是否当前已有事件
        if role_record.service_affair_id:
            raise GameException("当前已有事件")
        # 防止重复签到
        current_bind_seat_record = SeatRepository.get_by_service_role_guid(rid)
        if current_bind_seat_record:
            raise GameException("当前已绑定座位")
        # 当前座位是否已绑定
        seat_record = SeatRepository.get_by_seat_id(seat_id)
        if not seat_record:
            raise GameException("座位id错误")
        if seat_record.service_role_guid:
            raise GameException("当前座位已有服务者")

        # 座位加锁防止并发
        with mutex.KeyMutex(SeatIdLock.U_SEAT_ID_LOCK.format(SeatId=seat_id)):
            with PeeweeTransaction(propagation=TransactionPropagation.REQUIRES_NEW):
                # 创建服务者事件
                service_affair = ServiceRoleAffairRepository.create(rid, seat_id)
                # 绑定座位
                seat_record.service_role_guid = rid
                SeatRepository.save(seat_record)
                # 绑定事件
                role_record.service_affair_id = service_affair.affair_id
                RoleRepository.save(role_record)

        # 返回当前剩余座位数量
        return {}

    def clean_service_role(self, service_role_guid):
        """
        服务者结算
        :return:
        """

        result = {}
        role_record = RoleRepository.get_by_rid(service_role_guid)
        if not role_record or not role_record.is_service:
            raise GameException("无资格")
        if not role_record.service_affair_id:
            raise GameException("当前未绑定事件")
        service_affair = ServiceRoleAffairRepository.get_by_affair_id(role_record.service_affair_id)
        if not service_affair:
            raise GameException("事件不存在")

        # 是否已结算
        if service_affair.affair_status == ServiceAffairStatus.Close:
            role_record.service_affair_id = ""
            RoleRepository.save(role_record)
            raise GameException("已结算")

        seat_record = SeatRepository.get_by_service_role_guid(service_role_guid)
        if not seat_record:
            raise GameException("当前座位无此人")

        # 赏金计算
        reward = 1

        # 座位表清除
        seat_record.service_role_guid = ""
        # 结算时间记录
        service_affair.end_time = getCT()
        # 赏金记录
        service_affair.reward = reward
        # 修改状态
        service_affair.affair_status = ServiceAffairStatus.Close
        # 取消事件绑定
        role_record.service_affair_id = ""
        # 增加余额
        role_record.amount += reward

        # 计数
        service_time = int(math.ceil(getCountdown(service_affair.end_time, service_affair.sign_time) / 60))
        role_record.service_time += service_time
        role_record.service_times += len(service_affair.service_role_list)

        with PeeweeTransaction(propagation=TransactionPropagation.REQUIRES_NEW):
            SeatRepository.save(seat_record)
            RoleRepository.save(role_record)
            ServiceRoleAffairRepository.save(service_affair)

        result['Amount'] = role_record.amount

        return result

    def order_send(self, role_guid, game_id, server_type, server_id, order_type, price, need_time, safe_price,
                   quick_price, game_account, game_password, mobile, game_nickname, title, game_des):
        """
        发单
        """
        role_record = OrderSendRepository.create(role_guid=role_guid, game_id=game_id, server_type=server_type,
                                                 server_id=server_id, order_type=order_type, price=price,
                                                 need_time=need_time, safe_price=safe_price, quick_price=quick_price,
                                                 game_account=game_account, game_password=game_password, mobile=mobile,
                                                 game_nickname=game_nickname, title=title, game_des=game_des)
        return {"Role": role_record.asdict()}

    @staticmethod
    def enter_order_list_interface(page, page_size, order_column=""):
        """
        进入接单列表 (支持分页)

        :param page:
        :param page_size:
        :param order_column:
        :return:
        """

        # 偏移量
        offset = (page - 1) * page_size
        records = OrderSendRepository.filter_order_by_column(page_size, offset, order_column)
        order_list = []
        if not records:
            return {"status": True, "OrderList": order_list}

        rids = [record.role_guid for record in records]
        role_records = RoleRepository.filter_by_rid_list(rids)
        # 构造映射
        role_map_dict = {}
        for role in role_records:
            if role.role_guid not in role_map_dict:
                role_map_dict[role.role_guid] = role

        for r in records:
            role_obj = role_map_dict.get(r.role_guid)
            order_list.append({"GameId": r.game_id, "ServerType": r.server_type,
                               "ServerId": r.server_id, "OrderType": r.order_type,
                               "Title": r.title, "Price": r.price, "NickName": role_obj.nick_name if role_obj else "",
                               "NeedTime": r.need_time, "SafePrice": r.safe_price,
                               "QuickPrice": r.quick_price, "GameAccount": r.game_account,
                               "GamePassword": r.game_password, "GameNickName": r.game_nickname,
                               "Mobile": r.mobile, "GameDes": r.game_des,
                               })

        return {"status": True, "OrderList": order_list}

    def enter_person_info_interface(self, rid):
        """
        进入个人资料页
        :param rid:
        :return:
        """
        result = dict()
        role_record = RoleRepository.get_by_rid(rid)
        if not role_record:
            raise GameException("角色不存在")

        result['Head'] = role_record.head
        result['NickName'] = role_record.nick_name
        return result
